import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { EntityManager, Repository } from 'typeorm';
import {
  ConflictException,
  ForbiddenException,
  InternalServerErrorException,
  NotFoundException,
  UnauthorizedException,
} from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import { JwtPayload } from '../jwt/jwt-payload.interface';
import { GetUserFilterDto } from './dto/getUserFilterDto';
import { LoginDto } from './dto/login.dto';
import { updateUser, UserAllDto } from './dto/userAll.dto';
import { IPaginationOptions, paginate, Pagination } from '../utils/paginate';
import { isPhoneNumber, isEmail } from '../utils/validators/validators';
import { HttpService } from '@nestjs/axios';
import { witService } from '../utils/wit';
import { UpdatePasswordDto } from './dto/updatePassword.dto';

export class UsersRepository {
  constructor(
    @InjectRepository(User)
    protected repository: Repository<User>,
    protected jwtService: JwtService,
    private entityManage: EntityManager,
    protected readonly httpService: HttpService,
    protected readonly wit: witService,
  ) {}
  async getUserList(
    filterDto: GetUserFilterDto,
    options: IPaginationOptions,
  ): Promise<Pagination<User>> {
    const { search } = filterDto;
    const query = this.repository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.theme', 'theme', 'theme.isDelete = 0')
      .leftJoinAndSelect('user.roles', 'role', 'role.isDelete = 0');
    // if (status) {
    //   query.andWhere('user.id = :status', { status });
    // }
    if (search) {
      //'LOWER(user.username) LIKE LOWER(:search) OR LOWER(user.description) LIKE LOWER(:search)'
      query.andWhere(
        'LOWER(user.username) LIKE LOWER(:search) OR LOWER(user.account) LIKE LOWER(:search)',
        {
          search: `%${search}%`,
        },
      );
    }
    return await paginate<User>(query, options);
  }
  /**
   * 获取指定id用户信息
   * @param id
   */
  async getUserById(id: string): Promise<User> {
    const found = await this.repository
      .createQueryBuilder('user')
      .where({ id: id, isDelete: 0 })
      .getOne();
    if (!found) {
      throw new NotFoundException(`参数${id}没有找到！`);
    }
    return await this.getUserInfo(found);
  }

  /**
   * 获取当前登录用户信息
   * @param user
   */
  async getUserInfo(user: User): Promise<User> {
    const found = await this.repository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.theme', 'theme', 'theme.isDelete = 0')
      .leftJoinAndSelect('theme.background', 'background')
      .leftJoinAndSelect('theme.bar', 'bar')
      .leftJoinAndSelect('theme.custom', 'custom')
      .leftJoinAndSelect('theme.button', 'button')
      .leftJoinAndSelect('theme.config', 'config')
      // .where('theme.userId = :id AND theme.status = true', { id: user.id })
      .leftJoinAndSelect('user.roles', 'role', 'role.isDelete = 0')
      .leftJoinAndSelect('role.menu', 'menu', 'menu.isDelete = 0')
      // .leftJoinAndSelect('menu.children', 'children')
      .andWhere({ id: user.id, isDelete: 0 })
      .getOne();
    if (!found) {
      throw new NotFoundException(`获取用户信息失败！`);
    }
    // found.roles.menu = this.wit.handleTree(found.roles.menu);
    return found;
  }
  async deleteUser(id: string): Promise<void> {
    const result = await this.repository.delete(id);
    if (result.affected === 0) {
      throw new NotFoundException(`参数 ${id} 没有找到！`);
    }
  }

  /**
   * 修改当前用户信息
   * @param userAllDto
   * @param user
   */
  async updateUser(userAllDto: UserAllDto, user: User): Promise<User> {
    await this.repository
      .createQueryBuilder()
      .update(User)
      .set(userAllDto)
      .where('id = :id', { id: user.id })
      .execute();
    // await this.repository.save(users);
    return this.getUserInfo(user);
  }

  /**
   * 根据用户id修改用户信息
   * @param userAllDto
   * @param user
   */
  async updateUserById(userAllDto: updateUser, user: User): Promise<User> {
    const { id } = userAllDto;
    await this.repository
      .createQueryBuilder()
      .update(User)
      .set(userAllDto)
      .where('id = :id', { id: id })
      .execute();
    // await this.repository.save(users);
    return this.getUserById(id);
  }
  async updateUserPassword(updatePassword: UpdatePasswordDto, user: User) {
    const { password, id, passwordTow } = updatePassword;
    if (password === passwordTow) {
      // hash
      const salt = await bcrypt.genSalt();
      updatePassword.password = await bcrypt.hash(password, salt);
    } else {
      throw new ConflictException('两次密码不一致！');
    }
    const userPass = this.repository.create({
      id,
      password,
    });
    try {
      await this.repository.save(userPass);
    } catch (error) {
      throw new InternalServerErrorException('内部服务器错误异常');
    }
    return '密码修改成功！';
  }
  /** 公众接口，不需要授权
   * 创建用户/注册用户
   * @param createUserDto
   */
  async createUser(createUserDto: CreateUserDto): Promise<User> {
    const { password, email, phoneNum } = createUserDto;
    if (email) {
      if (!isEmail(email)) {
        throw new ConflictException('邮箱格式不正确！');
      }
    }
    if (phoneNum) {
      if (!isPhoneNumber(phoneNum)) {
        throw new ConflictException('手机号格式不正确！');
      }
    }
    // hash
    const salt = await bcrypt.genSalt();
    createUserDto.password = await bcrypt.hash(password, salt);
    const user = this.repository.create(createUserDto);
    try {
      await this.repository.save(user);
    } catch (error) {
      // console.log4js(error);
      if (error.code === '23505' || error.code === 'ER_DUP_ENTRY') {
        // 重复用户名
        throw new ConflictException('该用户名已存在！');
      } else {
        throw new InternalServerErrorException('内部服务器错误异常');
      }
    }
    return user;
  }

  /** 公众接口，不需要授权
   *  登录，返回token
   * @param loginDto
   */
  async signIn(loginDto: LoginDto): Promise<{ token: string }> {
    let user;
    const { account, password } = loginDto;
    if (isPhoneNumber(account)) {
      user = await this.repository.findOneBy({ phoneNum: account });
    } else if (isEmail(account)) {
      user = await this.repository.findOneBy({ email: account });
    } else {
      user = await this.repository.findOneBy({ account: account });
    }
    if (!user) {
      throw new ForbiddenException(`账号${account}不存在！`);
    }
    if (user.status === 0) {
      throw new ForbiddenException('账号已禁用，请联系管理员！');
    }
    if (user && (await bcrypt.compare(password, user.password))) {
      const payload: JwtPayload = { account };
      const token: string = this.jwtService.sign(payload);
      return { token };
    } else {
      throw new UnauthorizedException('用户名或密码输入错误！');
    }
  }
}
